home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
mach
/
sun3.md
/
machCode.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
56KB
|
1,843 lines
/*
* machCode.c --
*
* C code for the mach module.
*
* Copyright 1989 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/mach/sun3.md/machCode.c,v 9.19 91/10/10 12:08:22 shirriff Exp $ SPRITE (Berkeley)";
#endif /* not lint */
#include <sprite.h>
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <machConst.h>
#include <machMon.h>
#include <machInt.h>
#include <mach.h>
#include <sys.h>
#include <sync.h>
#include <dbg.h>
#include <proc.h>
#include <procMigrate.h>
#include <prof.h>
#include <sched.h>
#include <vm.h>
#include <vmMach.h>
#include <sig.h>
#include <swapBuffer.h>
#include <user/sigMach.h>
#include <user/sun3.md/sys/machSignal.h>
#include <procUnixStubs.h>
#include <compatInt.h>
#include <sigUnixStubs.h>
int machLastSP, machPOP;
/*
* Number of processors in the system.
*/
#ifndef NUM_PROCESSORS
#define NUM_PROCESSORS 1
#endif /* NUM_PROCESSORS */
int mach_NumProcessors = NUM_PROCESSORS;
/*
* TRUE if cpu was in kernel mode before the interrupt, FALSE if was in
* user mode.
*/
Boolean mach_KernelMode;
/*
* Flag used by routines to determine if they are running at
* interrupt level.
*/
Boolean mach_AtInterruptLevel = FALSE;
extern int debugProcStubs;
/*
* The machine type string is imported by the file system and
* used when expanding $MACHINE in file names.
*/
#ifdef sun3
char *mach_MachineType = "sun3";
#endif
#ifdef sun2
char *mach_MachineType = "sun2";
#endif
extern int debugProcStubs;
/*
* The byte ordering/alignment type used with Fmt_Convert and I/O control data
*/
Fmt_Format mach_Format = FMT_68K_FORMAT;
/*
* Count of number of ``calls'' to enable interrupts minus number of calls
* to disable interrupts. Kept on a per-processor basis.
*/
int mach_NumDisableInterrupts[NUM_PROCESSORS];
int *mach_NumDisableIntrsPtr = mach_NumDisableInterrupts;
/*
* The format that the kernel stack has to be in to start a process off.
*/
typedef struct {
int magicNumber; /* Magic number used to determine if
* the stack has been corrupted. */
Address userStackPtr; /* The user's stack pointer. */
short statusReg; /* The status register. */
void (*startFunc)(); /* Function to call when process
* first starts executing. */
int retPC; /* Return PC that will be sitting on the
* stack when startFunc is called. */
Address startPC; /* PC to start executing at. Is passed
* as an argument to startFunc. */
int fill1; /* Filler for the debugger. */
int fill2; /* Filler for the debugger. */
} KernelStack;
/*
* The format of a signal stack that is pushed onto a user's stack when
* a signal is handled.
*/
typedef struct {
Address retAddr;
Sig_Stack sigStack;
Sig_Context sigContext;
} SignalStack;
typedef struct UnixSignalStack {
int sigNum;
int sigCode;
struct sigcontext *sigContextPtr;
int sigAddr;
struct sigcontext sigContext;
} UnixSignalStack;
/*
* Machine dependent variables.
*/
Address mach_KernStart;
Address mach_CodeStart;
Address mach_StackBottom;
int mach_KernStackSize;
Address mach_KernEnd;
Address mach_FirstUserAddr;
Address mach_LastUserAddr;
Address mach_MaxUserStackAddr;
int mach_LastUserStackPage;
extern int MachGetVBR();
MachVectorTable *machVectorTablePtr;
int ((*machInterruptRoutines[256])());
ClientData machInterruptArgs[256];
/*
* The variables and tables below are used by the assembler routine
* in machTrap.s that dispatches kernel calls. All of this information
* is shared with machTrap.s; if you change any of this, be sure to
* change the assembler to match.
*/
#define MAXCALLS 120
#define MAXARGS 16
int machMaxSysCall; /* Highest defined system call. */
int machArgOffsets[MAXCALLS]; /* For each system call, tells how much
* to add to the sp at the time of the
* call to get to the highest argument
* on the stack. */
Address machArgDispatch[MAXCALLS]; /* For each system call, gives an
* address to branch to, in the middle
* of MachFetchArgs, to copy the right
* # of args from user space to the
* kernel's stack. */
ReturnStatus (*(mach_NormalHandlers[MAXCALLS]))();
/* For each system call, gives the
* address of the routine to handle
* the call for non-migrated processes.
*/
ReturnStatus (*(mach_MigratedHandlers[MAXCALLS]))();
/* For each system call, gives the
* address of the routine to handle
* the call for migrated processes. */
int machKcallTableOffset; /* Byte offset of the kcallTable field
* in a Proc_ControlBlock. */
int machStatePtrOffset; /* Byte offset of the machStatePtr
* field in a Proc_ControlBlock. */
int machSpecialHandlingOffset; /* Byte offset of the specialHandling
* field in a Proc_ControlBlock. */
/*
* Pointer to the state structure for the current process.
*/
Mach_State *machCurStatePtr = (Mach_State *)NIL;
MachMonBootParam machMonBootParam;
static void SetupSigHandler _ARGS_((register Proc_ControlBlock *procPtr, register SignalStack *sigStackPtr, Address pc));
static void ReturnFromSigHandler _ARGS_((register Proc_ControlBlock *procPtr));
/*
* ----------------------------------------------------------------------------
*
* Mach_Init --
*
* Initialize the exception vector table and some of the dispatching
* tables.
*
* Results:
* None.
*
* Side effects:
* The exception vector table is initialized.
*
* ----------------------------------------------------------------------------
*/
void
Mach_Init()
{
int *vecTablePtr;
int *protoVecTablePtr;
int i;
int offset;
/*
* Set exported machine dependent variables.
*/
mach_KernStart = (Address)MACH_KERN_START;
mach_KernEnd = (Address)MACH_KERN_END;
mach_CodeStart = (Address)MACH_CODE_START;
mach_StackBottom = (Address)MACH_STACK_BOTTOM;
mach_KernStackSize = MACH_KERN_STACK_SIZE;
mach_FirstUserAddr = (Address)MACH_FIRST_USER_ADDR;
mach_LastUserAddr = (Address)MACH_LAST_USER_ADDR;
mach_MaxUserStackAddr = (Address)MACH_MAX_USER_STACK_ADDR;
mach_LastUserStackPage = (MACH_MAX_USER_STACK_ADDR - 1) / VMMACH_PAGE_SIZE;
/*
* Copy the boot parameter structure. The original location will get
* unmapped during vm initialization so we need to get our own copy.
*/
machMonBootParam = **(romVectorPtr->bootParam);
offset = (int) *(romVectorPtr->bootParam) - (int) &(machMonBootParam);
for (i = 0; i < 8; i++) {
if (machMonBootParam.argPtr[i] != (char *) 0 &&
machMonBootParam.argPtr[i] != (char *) NIL) {
machMonBootParam.argPtr[i] -= offset;
}
}
/*
* Clear out the line input buffer to the prom so we don't get extra
* characters at the end of shorter reboot strings.
*/
bzero((Address) romVectorPtr->lineBuf, *romVectorPtr->lineSize);
/*
* Initialize the vector table.
*/
vecTablePtr = (int *) MachGetVBR();
machVectorTablePtr = (MachVectorTable *) vecTablePtr;
protoVecTablePtr = (int *) &machProtoVectorTable;
for (i = 0; i < MACH_NUM_EXCEPTIONS; i++) {
if (*protoVecTablePtr != 0) {
*vecTablePtr = *protoVecTablePtr;
}
vecTablePtr++;
protoVecTablePtr++;
}
#ifdef sun3
/*
* Initialize the autovector interrupt slots.
*/
for (i = MACH_NUM_EXCEPTIONS ; i<256 ; i++) {
extern int MachBrkptTrap();
*vecTablePtr = (int)MachBrkptTrap;
vecTablePtr++;
}
#endif sun3
#ifndef sun3
/*
* Put the vectors at the base of the kernel if are on a Sun-2 only. On
* a Sun-3 they can stay where they are. The vectors on the Sun-2 can
* be moved this easily because virtual address 0 which is where the
* vector table is at, points to the same physical page as virtual address
* mach_KernStart.
*/
MachSetVBR(mach_KernStart);
machVectorTablePtr = (MachVectorTable *) mach_KernStart;
#endif
/*
* Initialize some of the dispatching information. The rest is
* initialized by Mach_InitSysCall below.
*/
machMaxSysCall = -1;
machKcallTableOffset = (int) &((Proc_ControlBlock *) 0)->kcallTable;
machStatePtrOffset = (int) &((Proc_ControlBlock *) 0)->machStatePtr;
machSpecialHandlingOffset = (int)
&((Proc_ControlBlock *) 0)->specialHandling;
/*
* We start off with interrupts disabled.
*/
mach_NumDisableInterrupts[0] = 1;
}
/*
*----------------------------------------------------------------------
*
* Mach_InitFirstProc --
*
* Initialize the machine state struct for the very first process.
*
* Results:
* None.
*
* Side effects:
* Machine info allocated and stack start set up.
*
*----------------------------------------------------------------------
*/
void
Mach_InitFirstProc(procPtr)
Proc_ControlBlock *procPtr;
{
assert(offsetof(Proc_ControlBlock, unixErrno) == MACH_UNIX_ERRNO_OFFSET);
procPtr->machStatePtr = (Mach_State *)Vm_RawAlloc(sizeof(Mach_State));
bzero((Address) procPtr->machStatePtr, sizeof(*procPtr->machStatePtr));
procPtr->machStatePtr->kernStackStart = mach_StackBottom;
machCurStatePtr = procPtr->machStatePtr;
}
/*
*----------------------------------------------------------------------
*
* Mach_SetupNewState --
*
* Initialize the machine state for this process. This includes
* allocating and initializing a kernel stack. Assumed that will
* be called when starting a process after a fork or restarting a
* process after a migration.
*
* Results:
* PROC_NO_STACKS if couldn't allocate a kernel stack. SUCCESS otherwise.
*
* Side effects:
* Machine state in the destination process control block is overwritten.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Mach_SetupNewState(procPtr, fromStatePtr, startFunc, startPC, user)
Proc_ControlBlock *procPtr; /* Pointer to process control block
* to initialize state for. */
Mach_State *fromStatePtr; /* State of parent on fork or from
* other machine on migration. */
void (*startFunc)(); /* Function to call when process first
* starts executing. */
Address startPC; /* Address to pass as argument to
* startFunc. If NIL then the address
* is taken from *fromStatePtr's
* exception stack. */
Boolean user; /* TRUE if is a user process. */
{
register KernelStack *stackPtr;
register Mach_State *statePtr;
if (procPtr->machStatePtr == (Mach_State *)NIL) {
procPtr->machStatePtr = (Mach_State *)Vm_RawAlloc(sizeof(Mach_State));
}
bzero((Address) procPtr->machStatePtr, sizeof(*procPtr->machStatePtr));
statePtr = procPtr->machStatePtr;
/*
* Allocate a kernel stack for this process.
*/
statePtr->kernStackStart = Vm_GetKernelStack(0);
if (statePtr->kernStackStart == (Address)NIL) {
return(PROC_NO_STACKS);
}
statePtr->switchRegs[SP] = (int)(statePtr->kernStackStart +
MACH_KERN_STACK_SIZE -
sizeof(KernelStack));
/*
* Initialize the stack so that it looks like it is in the middle of
* Mach_ContextSwitch.
*/
stackPtr = (KernelStack *)(statePtr->switchRegs[SP]);
stackPtr->magicNumber = MAGIC;
stackPtr->userStackPtr = mach_MaxUserStackAddr;
stackPtr->statusReg = MACH_SR_HIGHPRIO;
stackPtr->startFunc = startFunc;
stackPtr->fill1 = 0;
stackPtr->fill2 = 0;
/*
* Set up the state of the process. User processes inherit from their
* parent or the migrated process. If the PC is not specified, take it
* from the parent as well.
*/
if (user) {
statePtr->userState.userStackPtr =
fromStatePtr->userState.userStackPtr;
bcopy((Address)fromStatePtr->userState.trapRegs,
(Address)statePtr->userState.trapRegs,
sizeof(statePtr->userState.trapRegs));
#ifdef sun3
bcopy((Address)fromStatePtr->userState.trapFpRegs,
(Address)statePtr->userState.trapFpRegs,
sizeof(statePtr->userState.trapFpRegs));
bcopy((Address)fromStatePtr->userState.trapFpCtrlRegs,
(Address)statePtr->userState.trapFpCtrlRegs,
sizeof(statePtr->userState.trapFpCtrlRegs));
bcopy((Address) &fromStatePtr->userState.trapFpuState,
(Address) &statePtr->userState.trapFpuState,
sizeof(statePtr->userState.trapFpuState));
#endif
}
if (startPC == (Address)NIL) {
stackPtr->startPC = (Address)fromStatePtr->userState.excStackPtr->pc;
} else {
stackPtr->startPC = startPC;
}
return(SUCCESS);
}
/*
*----------------------------------------------------------------------
*
* Mach_SetReturnVal --
*
* Set the return value for a process from a system call. Intended to
* be called by the routine that starts a user process after a fork.
*
* Results:
* None.
*
* Side effects:
* Register D0 is set in the user registers.
*
*----------------------------------------------------------------------
*/
void
Mach_SetReturnVal(procPtr, retVal, retVal2)
Proc_ControlBlock *procPtr; /* Process to set return value for. */
int retVal; /* Value for process to return. */
int retVal2; /* Second return value. */
{
procPtr->machStatePtr->userState.trapRegs[D0] = retVal;
procPtr->machStatePtr->userState.trapRegs[D1] = retVal2;
}
/*
*----------------------------------------------------------------------
*
* Mach_StartUserProc --
*
* Start a user process executing for the first time.
*
* Results:
* None.
*
* Side effects:
* Stack pointer and the program counter set for the process and
* the current process's image is replaced.
*
*----------------------------------------------------------------------
*/
void
Mach_StartUserProc(procPtr, entryPoint)
Proc_ControlBlock *procPtr; /* Process control block for process
* to start. */
Address entryPoint; /* Where process is to start
* executing. */
{
register Mach_State *statePtr;
register Mach_ExcStack *excStackPtr;
statePtr = procPtr->machStatePtr;
excStackPtr = (Mach_ExcStack *)
(statePtr->kernStackStart + MACH_BARE_STACK_OFFSET - MACH_SHORT_SIZE);
statePtr->userState.excStackPtr = excStackPtr;
statePtr->userState.trapRegs[SP] = (int)excStackPtr;
excStackPtr->statusReg = 0;
excStackPtr->pc = (int)entryPoint;
excStackPtr->vor.stackFormat = MACH_SHORT;
MachUserReturn(procPtr);
MachRunUserProc();
/* THIS DOES NOT RETURN */
}
/*
*----------------------------------------------------------------------
*
* Mach_ExecUserProc --
*
* Replace the calling user process's image with a new one.
*
* Results:
* None.
*
* Side effects:
* Stack pointer set for the process.
*
*----------------------------------------------------------------------
*/
void
Mach_ExecUserProc(procPtr, userStackPtr, entryPoint)
Proc_ControlBlock *procPtr; /* Process control block for
* process to exec. */
Address userStackPtr; /* Stack pointer for when the
* user process resumes
* execution. */
Address entryPoint; /* Where the user process is
* to resume execution. */
{
procPtr->machStatePtr->userState.userStackPtr = userStackPtr;
Mach_StartUserProc(procPtr, entryPoint);
/* THIS DOES NOT RETURN */
}
/*
*----------------------------------------------------------------------
*
* Mach_FreeState --
*
* Free up the machine state for the given process control block.
*
* Results:
* None.
*
* Side effects:
* Free up the kernel stack.
*
*----------------------------------------------------------------------
*/
void
Mach_FreeState(procPtr)
Proc_ControlBlock *procPtr; /* Process control block to free
* machine state for. */
{
if (procPtr->machStatePtr->kernStackStart != (Address)NIL) {
Vm_FreeKernelStack(procPtr->machStatePtr->kernStackStart);
procPtr->machStatePtr->kernStackStart = (Address)NIL;
}
}
/*
*----------------------------------------------------------------------
*
* Mach_CopyState --
*
* Copy the state from the given state structure to the machine
* state structure for the destination process control block. Intended
* to be used by the debugger to modify the state.The only fields
* that can be modified are the following:
*
* 1) user stack pointer
* 2) all trap registers except for the stack pointer because the
* stack pointer in the trap registers is the kernel stack pointer.
* 3) the PC, VOR and status register in the exception stack.
*
* Results:
* None.
*
* Side effects:
* Machine state in the destination process control block is overwritten.
*
*----------------------------------------------------------------------
*/
void
Mach_CopyState(statePtr, destProcPtr)
Mach_State *statePtr; /* Pointer to state to copy from. */
Proc_ControlBlock *destProcPtr; /* Process control block to copy
* state to. */
{
register Mach_State *destStatePtr;
destStatePtr = destProcPtr->machStatePtr;
destStatePtr->userState.userStackPtr =
statePtr->userState.userStackPtr;
bcopy((Address)statePtr->userState.trapRegs,
(Address)destStatePtr->userState.trapRegs,
sizeof(int) * (MACH_NUM_GPRS - 1));
#ifdef sun3
bcopy((Address)statePtr->userState.trapFpRegs,
(Address)destStatePtr->userState.trapFpRegs,
sizeof(statePtr->userState.trapFpRegs));
bcopy((Address)statePtr->userState.trapFpCtrlRegs,
(Address)destStatePtr->userState.trapFpCtrlRegs,
sizeof(statePtr->userState.trapFpCtrlRegs));
bcopy((Address) &statePtr->userState.trapFpuState,
(Address) &destStatePtr->userState.trapFpuState,
sizeof(statePtr->userState.trapFpuState));
#endif
destStatePtr->userState.excStackPtr->pc =
statePtr->userState.excStackPtr->pc;
destStatePtr->userState.excStackPtr->statusReg =
statePtr->userState.excStackPtr->statusReg;
}
/*
*----------------------------------------------------------------------
*
* Mach_GetDebugState --
*
* Extract the appropriate fields from the machine state struct
* and store them into the debug struct.
*
* Results:
* None.
*
* Side effects:
* Debug struct filled in from machine state struct.
*
*----------------------------------------------------------------------
*/
void
Mach_GetDebugState(procPtr, debugStatePtr)
Proc_ControlBlock *procPtr;
Proc_DebugState *debugStatePtr;
{
register Mach_State *machStatePtr;
machStatePtr = procPtr->machStatePtr;
bcopy((Address)machStatePtr->userState.trapRegs,
(Address)debugStatePtr->regState.regs,
sizeof(machStatePtr->userState.trapRegs));
debugStatePtr->regState.regs[SP] =
(int)machStatePtr->userState.userStackPtr;
debugStatePtr->regState.pc = machStatePtr->userState.excStackPtr->pc;
debugStatePtr->regState.statusReg =
machStatePtr->userState.excStackPtr->statusReg;
}
/*
*----------------------------------------------------------------------
*
* Mach_SetDebugState --
*
* Extract the appropriate fields from the debug struct
* and store them into the machine state struct.
*
* Results:
* None.
*
* Side effects:
* Machine state struct filled in from the debug state struct.
*
*----------------------------------------------------------------------
*/
void
Mach_SetDebugState(procPtr, debugStatePtr)
Proc_ControlBlock *procPtr;
Proc_DebugState *debugStatePtr;
{
register Mach_State *machStatePtr;
machStatePtr = procPtr->machStatePtr;
bcopy((Address)debugStatePtr->regState.regs,
(Address)machStatePtr->userState.trapRegs,
sizeof(machStatePtr->userState.trapRegs) - sizeof(int));
machStatePtr->userState.userStackPtr =
(Address)debugStatePtr->regState.regs[SP];
machStatePtr->userState.excStackPtr->pc =
debugStatePtr->regState.pc;
if (!(debugStatePtr->regState.statusReg & MACH_SR_SUPSTATE)) {
machStatePtr->userState.excStackPtr->statusReg =
debugStatePtr->regState.statusReg;
}
}
/*
* ----------------------------------------------------------------------------
*
* Mach_GetUserStackPtr --
*
* Return the user stack pointer from the machine state struct for the
* given process.
*
* Results:
* The value of the user stack pointer when the process trapped.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
Address
Mach_GetUserStackPtr(procPtr)
Proc_ControlBlock *procPtr;
{
return(procPtr->machStatePtr->userState.userStackPtr);
}
/*
*----------------------------------------------------------------------
*
* Mach_InitSyscall --
*
* During initialization, this procedure is called once for each
* kernel call, in order to set up information used to dispatch
* the kernel call. This procedure must be called once for each
* kernel call, in order starting at 0.
*
* Results:
* None.
*
* Side effects:
* Initializes the dispatch tables for the kernel call.
*
*----------------------------------------------------------------------
*/
void
Mach_InitSyscall(callNum, numArgs, normalHandler, migratedHandler)
int callNum; /* Number of the system call. */
int numArgs; /* Number of one-word arguments passed
* into call on stack. */
ReturnStatus (*normalHandler)(); /* Procedure to process kernel call
* when process isn't migrated. */
ReturnStatus (*migratedHandler)(); /* Procedure to process kernel call
* for migrated processes. */
{
machMaxSysCall++;
if (machMaxSysCall != callNum) {
printf("Warning: out-of-order kernel call initialization, call %d\n",
callNum);
}
if (machMaxSysCall >= MAXCALLS) {
printf("Mach_InitSyscall: too many kernel calls\n",
machMaxSysCall);
machMaxSysCall--;
return;
}
if (numArgs > MAXARGS) {
printf("Mach_InitSyscall: too many arguments (%d) to kernel call <%d>\n",
numArgs, callNum);
numArgs = MAXARGS;
}
/*
* MachArgOffsets and machArgDispatch below are used in MachSyscallTrap
* to do a very quick dispatch to copy arguments from the user stack
* to the kernel stack. machArgOffsets is used to locate the first
* argument on the user's stack, and machArgDispatch is used to branch
* into the middle of an unwound loop to do the copy. See the
* argument-copying code in MachSyscallTrap for more details.
*/
machArgOffsets[machMaxSysCall] = 8 + numArgs*4;
machArgDispatch[machMaxSysCall] =
(16-numArgs)*2 + (Address) MachFetchArgs;
mach_NormalHandlers[machMaxSysCall] = normalHandler;
mach_MigratedHandlers[machMaxSysCall] = migratedHandler;
}
/*
* ----------------------------------------------------------------------------
*
* Mach_SetHandler --
*
* Put a device driver interrupt handling routine into the autovector.
*
* Results:
* None.
*
* Side effects:
* The exception vector table is modified.
*
* ----------------------------------------------------------------------------
*/
void
Mach_SetHandler(vectorNumber, handler, clientData)
int vectorNumber; /* Vector number that the device generates */
int (*handler)(); /* Interrupt handling procedure */
ClientData clientData; /* ClientData for interrupt callback routine. */
{
int *vecTablePtr;
extern int MachVectoredInterrupt();
/*
* Don't let the caller override a vector than can't be generated with
* an interrupt. Only vectors 24 thru 30 and 64 thru 255 can be
* generated.
*/
if ((vectorNumber < 25) ||
((vectorNumber > 30) && (vectorNumber < 64)) ||
(vectorNumber > 255)) {
panic("Warning: Bad vector number %d\n",vectorNumber);
} else {
machInterruptRoutines[vectorNumber] = handler;
machInterruptArgs[vectorNumber] = clientData;
vecTablePtr = (int *) MachGetVBR();
vecTablePtr[vectorNumber] = (int)MachVectoredInterrupt;
}
}
/*
* ----------------------------------------------------------------------------
*
* MachTrap --
*
* The trap handler routine. This deals with supervisor mode and
* non-supervisor mode traps differently. The only allowed supervisor
* mode traps are a breakpoint trap to force a context switch and a
* bus error in the middle of a cross address space copy. All other
* traps go into the debugger. However, all types of user traps are
* processed here, except for system calls, which don't pass through
* this procedure unless special action (like a context switch) is
* needed at the end of the call.
*
* Results:
* MACH_KERN_ERROR if the debugger should be called after this routine
* returns, MACH_USER_ERROR if a copy to/from user space caused an
* unrecoverable bus error, and MACH_OK if everything worked out ok.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
MachTrap(trapStack)
Mach_TrapStack trapStack; /* The stack at the time of the trap.*/
{
register Proc_ControlBlock *procPtr;
ReturnStatus status;
procPtr = Proc_GetActualProc();
/*
* Process kernel traps.
*/
if (trapStack.excStack.statusReg & MACH_SR_SUPSTATE) {
switch (trapStack.trapType) {
case MACH_TRACE_TRAP:
/*
* If the trace trap occured on a user trap instruction, then
* the trace trap will be taken on the first instruction of
* the trap handler. When this trace trap occurs,
* instead of the saved status register being in user mode and
* having the trace trap bit set, the status register will
* be in kernel mode with no trace trap bit set.
* In this case we just ignore the trace trap because it
* will reoccur when the user process continues.
*/
if (!(trapStack.excStack.statusReg & MACH_SR_TRACEMODE)) {
return(MACH_OK);
}
/*
* In the normal case enter the debugger with a breakpoint
* trap.
*/
return(MACH_KERN_ERROR);
case MACH_BUS_ERROR:
if (trapStack.busErrorReg.timeOut) {
/*
* Allow for refresh memory time just like Unix.
*/
MACH_DELAY(2000);
}
/*
* Check to see if is a parity error.
*/
#ifndef sun3
if (trapStack.busErrorReg.parErrU || trapStack.busErrorReg.parErrL) {
panic("Parity error!!!\n");
return(MACH_KERN_ERROR);
}
if (trapStack.busErrorReg.busErr) {
panic("System bus error\n");
return(MACH_KERN_ERROR);
}
#endif
if (procPtr == (Proc_ControlBlock *)NIL) {
panic("MachTrap: Current process is NIL!! Trap PC 0x%x\n",
(unsigned) trapStack.excStack.pc);
}
if (procPtr->genFlags & PROC_USER) {
Boolean protError;
Boolean copyInProgress = FALSE;
/*
* A page fault on a user process while executing in
* the kernel. This can happen when information is
* being copied back and forth between kernel and
* user state (indicated by particular values of the
* program counter), after a pointer is made accessible by
* Vm_MakeAccessible (indicated by numMakeAcc > 0) or
* after someone did a Mach_Probe() in the kernel and tried
* to access a user process.
*/
if ((((Address) trapStack.excStack.pc) >=
(Address) Vm_CopyIn)
&& (((Address) trapStack.excStack.pc)
< (Address) VmMachCopyEnd)) {
copyInProgress = TRUE;
} else if ((((Address) trapStack.excStack.pc)
>= (Address) MachFetchArgs2)
&& (((Address) trapStack.excStack.pc)
<= (Address) MachFetchArgsEnd2)) {
copyInProgress = TRUE;
} else if ((((Address) trapStack.excStack.pc)
>= (Address) MachFetchArgs)
&& (((Address) trapStack.excStack.pc)
<= (Address) MachFetchArgsEnd)) {
copyInProgress = TRUE;
} else if ((((Address) trapStack.excStack.pc)
>= (Address) MachProbeStart)
&& (((Address) trapStack.excStack.pc)
<= (Address) MachProbeEnd)) {
return(MACH_USER_ERROR);
} else if (procPtr->vmPtr->numMakeAcc == 0) {
return(MACH_KERN_ERROR);
}
protError =
#ifdef sun3
!trapStack.busErrorReg.pageInvalid;
#else
trapStack.busErrorReg.resident;
#endif
/*
* Try to fault in the page.
*/
status = Vm_PageIn(
(Address)trapStack.excStack.tail.addrBusErr.faultAddr,
protError);
if (status != SUCCESS) {
if (copyInProgress) {
return(MACH_USER_ERROR);
} else {
/*
* Real kernel error.
*/
return(MACH_KERN_ERROR);
}
} else {
return(MACH_OK);
}
} else {
/*
* Happened to a kernel process. If the error happen
* in Mach_Probe() return MACH_USER_ERROR to force
* Mach_Probe() to return FAILURE.
*/
if ((((Address) trapStack.excStack.pc)
>= (Address) MachProbeStart)
&& (((Address) trapStack.excStack.pc)
<= (Address) MachProbeEnd)) {
return(MACH_USER_ERROR);
} else {
return(MACH_KERN_ERROR);
}
}
case MACH_SPURIOUS_INT:
/*
* Ignore this for now because otherwise we can't debug mint
*/
if (!dbg_BeingDebugged) {
printf("MachTrap: Spurious interrupt\n");
}
return(MACH_OK);
default:
return(MACH_KERN_ERROR);
}
}
/*
* Process user traps.
*/
/*
* Take a context switch if one is pending for this process.
*/
if (procPtr->schedFlags & SCHED_CONTEXT_SWITCH_PENDING) {
Sched_LockAndSwitch();
}
/*
* Now clear out the trace trap bit out of the status register. This is
* a precaution to take care of cases such as when a bus error occurs on
* the instruction that we are trying to trace such that the trace trap bit
* is set but we didn't get a trace trap exception.
*/
trapStack.excStack.statusReg &= ~MACH_SR_TRACEMODE;
switch (trapStack.trapType) {
case MACH_BUS_ERROR: {
Boolean protError;
if (trapStack.busErrorReg.timeOut) {
/*
* Allow for refresh memory time just like Unix.
*/
MACH_DELAY(2000);
}
/*
* Check for parity error.
*/
#ifndef sun3
if (trapStack.busErrorReg.parErrU || trapStack.busErrorReg.parErrL) {
panic("Parity error!!!\n");
return(MACH_KERN_ERROR);
}
#endif
/*
* Take a page fault. It is assumed that if the resident bit
* is set in the bus error register then this is a protection
* error.
*/
protError =
#ifdef sun3
!trapStack.busErrorReg.pageInvalid;
#else
trapStack.busErrorReg.resident;
#endif
if (Vm_PageIn((Address)trapStack.excStack.tail.addrBusErr.faultAddr,
protError) != SUCCESS) {
printf(
"MachTrap: Bus error in user proc %X, PC = %x, addr = %x BR Reg %x\n",
procPtr->processID,
trapStack.excStack.pc,
trapStack.excStack.tail.addrBusErr.faultAddr,
*(int *)&trapStack.busErrorReg);
(void) Sig_Send(SIG_ADDR_FAULT, SIG_ACCESS_VIOL,
procPtr->processID, FALSE,
(Address)trapStack.excStack.tail.addrBusErr.faultAddr);
}
break;
}
case MACH_UNIX_SYSCALL_TRAP:
case MACH_SYSCALL_TRAP:
/*
* It used to be that all system calls passed through here, but
* the code was optimized to avoid calling either this procedure
* or Sys_SysCall in the normal case. Control only passes through
* here if, at the end of a system call, it's discovered that
* special action must be taken. The call has already been
* executed by the time things arrive here. This code does
* nothing... the action will all be taken by the call to
* MachUserReturn below.
*/
break;
case MACH_BRKPT_TRAP:
Proc_Lock(procPtr);
if (procPtr->genFlags & PROC_DEBUG_ON_EXEC) {
procPtr->genFlags &= ~PROC_DEBUG_ON_EXEC;
(void) Sig_SendProc(procPtr, SIG_DEBUG, SIG_NO_CODE,
(Address)0);
} else {
(void) Sig_SendProc(procPtr, SIG_BREAKPOINT, SIG_NO_CODE,
(Address)0);
}
Proc_Unlock(procPtr);
break;
case MACH_SIG_RET_TRAP: {
/*
* We got a return from signal trap.
*/
ReturnFromSigHandler(procPtr);
return(MACH_SIG_RETURN);
}
case MACH_ADDRESS_ERROR:
(void) Sig_Send(SIG_ADDR_FAULT, SIG_ADDR_ERROR,
procPtr->processID, FALSE,
(Address)trapStack.excStack.tail.addrBusErr.faultAddr);
break;
case MACH_ILLEGAL_INST:
printf("Illegal instruction in %x at %x\n", procPtr->processID,
trapStack.excStack.pc);
(void) Sig_Send(SIG_ILL_INST, SIG_ILL_INST_CODE,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
break;
case MACH_ZERO_DIV:
(void) Sig_Send(SIG_ARITH_FAULT, SIG_ZERO_DIV,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
break;
case MACH_CHK_INST:
(void) Sig_Send(SIG_ILL_INST, SIG_CHK,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
break;
case MACH_TRAPV:
(void) Sig_Send(SIG_ILL_INST, SIG_TRAPV,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
break;
case MACH_PRIV_VIOLATION:
(void) Sig_Send(SIG_ILL_INST, SIG_PRIV_INST,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
break;
case MACH_TRACE_TRAP:
/*
* Involuntary context switch trace traps have already been taken
* care of above. Here the only time we pay attention to a
* trace trap is if the debugger is trying to single step the
* user process.
*/
if (procPtr->genFlags & PROC_SINGLE_STEP_FLAG) {
procPtr->genFlags &= ~PROC_SINGLE_STEP_FLAG;
(void) Sig_Send(SIG_TRACE_TRAP, SIG_NO_CODE,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
}
break;
case MACH_EMU1010:
(void) Sig_Send(SIG_ILL_INST, SIG_EMU1010,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
break;
case MACH_EMU1111:
(void) Sig_Send(SIG_ILL_INST, SIG_EMU1111,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
break;
case MACH_BAD_TRAP:
(void) Sig_Send(SIG_ILL_INST, SIG_BAD_TRAP,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
break;
#ifdef sun3
case MACH_FP_UNORDERED_COND:
(void) Sig_Send(SIG_ARITH_FAULT, SIG_FP_UNORDERED_COND,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
case MACH_FP_INEXACT_RESULT:
(void) Sig_Send(SIG_ARITH_FAULT, SIG_FP_INEXACT_RESULT,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
case MACH_FP_ZERO_DIV:
(void) Sig_Send(SIG_ARITH_FAULT, SIG_FP_ZERO_DIV,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
case MACH_FP_UNDERFLOW:
(void) Sig_Send(SIG_ARITH_FAULT, SIG_FP_UNDERFLOW,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
case MACH_FP_OPERAND_ERROR:
(void) Sig_Send(SIG_ARITH_FAULT, SIG_FP_OPERAND_ERROR,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
case MACH_FP_OVERFLOW:
(void) Sig_Send(SIG_ARITH_FAULT, SIG_FP_OVERFLOW,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
case MACH_FP_NAN:
(void) Sig_Send(SIG_ARITH_FAULT, SIG_FP_NAN,
procPtr->processID, FALSE,
(Address)trapStack.excStack.pc);
#endif
default:
return(MACH_KERN_ERROR);
}
MachUserReturn(procPtr);
return(MACH_OK);
}
/*
* ----------------------------------------------------------------------------
*
* MachUserReturn --
*
* Take the proper action to return from a user exception.
*
* Results:
* None.
*
* Side effects:
* Interrupts disabled.
*
* ----------------------------------------------------------------------------
*/
void
MachUserReturn(procPtr)
register Proc_ControlBlock *procPtr;
{
SignalStack sigStack;
Address pc;
int restarted=0;
if (procPtr->unixProgress != PROC_PROGRESS_NOT_UNIX &&
procPtr->unixProgress != PROC_PROGRESS_UNIX && debugProcStubs) {
printf("UnixProgress = %d entering MachUserReturn\n",
procPtr->unixProgress);
}
if (procPtr->Prof_Scale != 0 && procPtr->Prof_PC != 0) {
Prof_RecordPC(procPtr);
}
/*
* Take a context switch if one is pending for this process.
*/
if (procPtr->schedFlags & SCHED_CONTEXT_SWITCH_PENDING) {
Sched_LockAndSwitch();
}
/*
* Check for signals. Interrupts are disabled because we have to
* make sure that we don't miss a signal. Interrupts will be reenabled
* automatically upon the rte.
*/
while (TRUE) {
/*
* Disable interrupts. Note that we don't use the DISABLE_INTR macro
* because it increments the nesting depth of interrupts which we don't
* want because there is an implicit enable interrupts on rte.
*/
Mach_DisableIntr();
if (!Sig_Pending(procPtr)) {
break;
}
Mach_EnableIntr();
sigStack.sigStack.contextPtr = &sigStack.sigContext;
if (procPtr->unixProgress == PROC_PROGRESS_RESTART ||
procPtr->unixProgress > 0) {
/*
* If we received a normal signal, we want to restart
* the system call when we leave.
* If we received a migrate signal, we will get here on
* the new machine.
* We must also ensure that the argument registers are the
* same as when we came in.
*/
restarted = 1;
if (debugProcStubs) {
printf("Restarting system call with progress %d\n",
procPtr->unixProgress);
}
procPtr->unixProgress = PROC_PROGRESS_UNIX;
}
if (Sig_Handle(procPtr, &sigStack.sigStack, &pc)) {
if (procPtr->unixProgress != PROC_PROGRESS_NOT_UNIX) {
procPtr->unixProgress = PROC_PROGRESS_UNIX;
}
SetupSigHandler(procPtr, &sigStack, pc);
Mach_DisableIntr();
break;
} else {
if (procPtr->unixProgress == PROC_PROGRESS_MIG_RESTART ||
procPtr->unixProgress == PROC_PROGRESS_RESTART) {
restarted = 1;
if (debugProcStubs) {
printf("No signal action, so we restarted call\n");
}
procPtr->unixProgress = PROC_PROGRESS_UNIX;
} else if (restarted && debugProcStubs) {
printf("No signal, yet we restarted system call!\n");
}
}
}
if ((procPtr->genFlags & PROC_SINGLE_STEP_FLAG) ||
(procPtr->schedFlags & SCHED_CONTEXT_SWITCH_PENDING)) {
/*
* Set the trace trap bit if we are supposed to single-step this
* process or a context switch is pending. We check for a context
* switch pending here even though we just checked above just in
* case we got preempted while dealing with signals.
*/
procPtr->machStatePtr->userState.excStackPtr->statusReg |=
MACH_SR_TRACEMODE;
}
/*
* It is possible for Sig_Handle to mask the migration signal
* if a process is not in a state where it can be migrated.
* As soon as we return to user mode, though, we will allow migration.
*/
Sig_AllowMigration(procPtr);
if (restarted) {
if (debugProcStubs) {
printf("Moving the PC to restart the system call\n");
}
procPtr->machStatePtr->userState.excStackPtr->pc -= 4;
}
if (procPtr->unixProgress != PROC_PROGRESS_NOT_UNIX &&
procPtr->unixProgress != PROC_PROGRESS_UNIX && debugProcStubs) {
printf("UnixProgress = %d leaving MachUserReturn\n",
procPtr->unixProgress);
}
}
/*
* ----------------------------------------------------------------------------
*
* Routines to set up and return from signal handlers.
*
* In order to call a handler four things must be done:
*
* 1) The current state of the process must be saved so that when
* the handler returns a normal return to user space can occur.
* 2) The user stack must be set up so that the signal number and the
* the signal code are passed to the handler.
* 3) Things must be set up so that when the handler returns it returns
* back into the kernel so that state can be cleaned up.
* 4) The trap stack that was created when the kernel was entered and is
* used to return a process to user space must be modified so that
* the signal handler is called instead of executing the
* normal return.
*
* The last one is done by simply changing the program counter where the
* user process will execute on return to be the address of the signal
* handler and the user stack pointer to point to the proper place on
* the user stack. The first three of these are accomplished by
* setting up the user stack properly. The top entry on the stack is the
* return address where the handler will start executing upon return. But
* this is just the address of a trap instruction that is stored on the stack
* below. Thus when a handler returns it will execute a trap instruction
* and drop back into the kernel.
*/
/*
* ----------------------------------------------------------------------------
*
* SetupSigHandler --
*
* Save machine state on the users stack and set up the exception stack
* so that the user will call the signal handler on return. In order to
* Results:
* None.
*
* Side effects:
* Signal stack set up and saved.
*
* ----------------------------------------------------------------------------
*/
static void
SetupSigHandler(procPtr, sigStackPtr, pc)
register Proc_ControlBlock *procPtr;
register SignalStack *sigStackPtr;
Address pc;
{
register Mach_State *statePtr;
Address usp;
int excStackSize;
Mach_ExcStack *excStackPtr;
struct UnixSignalStack unixSigStack;
int unixSignal;
statePtr = procPtr->machStatePtr;
excStackSize = Mach_GetExcStackSize(statePtr->userState.excStackPtr);
if (procPtr->unixProgress != PROC_PROGRESS_NOT_UNIX) {
usp = (Address)statePtr->userState.userStackPtr -
sizeof(UnixSignalStack);
if (Compat_SpriteSignalToUnix(sigStackPtr->sigStack.sigNum, &unixSignal)
!= SUCCESS) {
printf("Signal %d invalid in SetupSigHandler\n",
sigStackPtr->sigStack.sigNum);
return;
}
if (debugProcStubs) {
printf("Unix signal %d(%d) to %x\n", unixSignal,
sigStackPtr->sigStack.sigNum, procPtr->processID);
}
unixSigStack.sigNum = unixSignal;
unixSigStack.sigCode = sigStackPtr->sigStack.sigCode;
unixSigStack.sigContextPtr = (struct sigcontext *)(usp + 4*sizeof(int));
unixSigStack.sigAddr = sigStackPtr->sigStack.sigAddr;
unixSigStack.sigContext.sc_onstack = 0;
unixSigStack.sigContext.sc_mask = 0;
unixSigStack.sigContext.sc_sp = (int) statePtr->userState.userStackPtr;
unixSigStack.sigContext.sc_pc =
(int) statePtr->userState.excStackPtr->pc;
unixSigStack.sigContext.sc_ps =
(int) statePtr->userState.excStackPtr->statusReg;
if (debugProcStubs) {
printf("sp = %x, pc = %x, ps = %x, len = %d to %x, exPc = %x\n",
statePtr->userState.userStackPtr, pc,
unixSigStack.sigContext.sc_ps, sizeof(UnixSignalStack),
(Address)usp, statePtr->userState.excStackPtr->pc);
}
/*
* Copy the stack out to user space.
*/
if (Vm_CopyOut(sizeof(UnixSignalStack), (Address)&unixSigStack,
(Address)usp) != SUCCESS) {
printf("Warning: HandleSig: No room on stack for signal, PID=%x.\n",
procPtr->processID);
Proc_ExitInt(PROC_TERM_DESTROYED, PROC_BAD_STACK, 0);
}
} else {
if (procPtr->unixProgress != PROC_PROGRESS_NOT_UNIX &&
debugProcStubs) {
printf("Warning: process %x has unixProgress = %x\n",
procPtr->processID, procPtr->unixProgress);
}
usp = statePtr->userState.userStackPtr - sizeof(SignalStack);
sigStackPtr->sigStack.contextPtr =
(Sig_Context *)(usp + (unsigned int)(&sigStackPtr->sigContext) -
(unsigned int)sigStackPtr);
/*
* We put the instruction TRAP 2 in trapInst, and then set
* the return address to point to that instruction.
* TRAP 2 does a ReturnFromSigHandler.
*/
sigStackPtr->sigContext.machContext.trapInst = 0x4e424e42;
sigStackPtr->retAddr =
usp + (unsigned int)(&sigStackPtr->sigContext.machContext.trapInst) -
(unsigned int)sigStackPtr;
/*
* Copy the exception stack onto the signal stack.
*/
bcopy((Address)statePtr->userState.excStackPtr,
(Address)&(sigStackPtr->sigContext.machContext.excStack),
excStackSize);
/*
* Copy the user state onto the signal stack.
*/
bcopy((Address)&statePtr->userState,
(Address)&(sigStackPtr->sigContext.machContext.userState),
sizeof(Mach_UserState));
/*
* Copy the stack out to user space.
*/
if (Vm_CopyOut(sizeof(SignalStack), (Address)sigStackPtr,
(Address)usp) != SUCCESS) {
printf("Warning: HandleSig: No room on stack for signal, PID=%x.\n",
procPtr->processID);
Proc_ExitInt(PROC_TERM_DESTROYED, PROC_BAD_STACK, 0);
}
}
/*
* We need to make a short stack to allow the process to start executing.
* The current exception stack is at least as big, maybe bigger than we
* need. Since we saved the true exception stack above, we can just
* overwrite the current stack with a short stack and point the stack
* pointer at it.
*/
if (statePtr->userState.excStackPtr !=
(Mach_ExcStack *)statePtr->userState.trapRegs[SP]) {
panic("Mach_HandleSig: SP != excStackPtr\n");
}
statePtr->userState.userStackPtr = usp;
excStackPtr = (Mach_ExcStack *) ((Address)statePtr->userState.excStackPtr +
excStackSize - MACH_SHORT_SIZE);
statePtr->userState.trapRegs[SP] = (int)excStackPtr;
excStackPtr->statusReg = 0;
excStackPtr->vor.stackFormat = MACH_SHORT;
excStackPtr->pc = (int)pc;
}
/*
* ----------------------------------------------------------------------------
*
* ReturnFromSigHandler --
*
* Process a return from a signal handler.
*
* Results:
* None.
*
* Side effects:
* Signal stack struct and size filled in the machine struct for the
* given process.
*
* ----------------------------------------------------------------------------
*/
static void
ReturnFromSigHandler(procPtr)
register Proc_ControlBlock *procPtr;
{
register Mach_State *statePtr;
int curSize;
int oldSize;
SignalStack sigStack;
statePtr = procPtr->machStatePtr;
if (procPtr->unixProgress == PROC_PROGRESS_UNIX) {
/*
* Unix dynamic linking does a trap#2 for no apparent reason.
*/
return;
}
/*
* Copy the signal stack in.
*/
if (Vm_CopyIn(sizeof(Sig_Stack) + sizeof(Sig_Context),
(Address) (statePtr->userState.userStackPtr),
(Address) &sigStack.sigStack) != SUCCESS) {
printf("%s Mach_Code: Stack too small to extract trap info, PID=%x.\n",
"Warning:", procPtr->processID);
Proc_ExitInt(PROC_TERM_DESTROYED, PROC_BAD_STACK, 0);
}
sigStack.sigStack.contextPtr = &sigStack.sigContext;
/*
* Take the proper action on return from a signal.
*/
Sig_Return(procPtr, &sigStack.sigStack);
/*
* Restore user state. Be careful not to clobber the stack
* pointer.
*/
statePtr->userState.userStackPtr =
sigStack.sigContext.machContext.userState.userStackPtr;
bcopy((Address)sigStack.sigContext.machContext.userState.trapRegs,
(Address)statePtr->userState.trapRegs,
sizeof(int) * (MACH_NUM_GPRS - 1));
#ifdef sun3
bcopy((Address)sigStack.sigContext.machContext.userState.trapFpRegs,
(Address)statePtr->userState.trapFpRegs,
sizeof(statePtr->userState.trapFpRegs));
bcopy((Address)sigStack.sigContext.machContext.userState.trapFpCtrlRegs,
(Address)statePtr->userState.trapFpCtrlRegs,
sizeof(statePtr->userState.trapFpCtrlRegs));
bcopy((Address) &sigStack.sigContext.machContext.userState.trapFpuState,
(Address) &statePtr->userState.trapFpuState,
sizeof(statePtr->userState.trapFpuState));
#endif
/*
* Verify that the exception stack is OK.
*/
curSize = Mach_GetExcStackSize(statePtr->userState.excStackPtr);
oldSize = Mach_GetExcStackSize(&sigStack.sigContext.machContext.excStack);
if (oldSize == -1) {
printf("Mach_Code: Bad signal stack type.\n");
Proc_ExitInt(PROC_TERM_DESTROYED, PROC_BAD_STACK, 0);
}
if (sigStack.sigContext.machContext.excStack.statusReg & MACH_SR_SUPSTATE) {
printf("Mach_Code: User set kernel bit on signal stack\n");
Proc_ExitInt(PROC_TERM_DESTROYED, PROC_BAD_STACK, 0);
}
/*
* Copy the exception stack in.
*/
bcopy((Address)&sigStack.sigContext.machContext.excStack,
(Address)&statePtr->sigExcStack, oldSize);
statePtr->sigExcStackSize = oldSize;
/*
* Set the restored stack pointer to point to where the
* old exception stack is to be restored to.
*/
statePtr->userState.trapRegs[SP] += curSize - oldSize;
}
/*
* ----------------------------------------------------------------------------
*
* Mach_GetExcStackSize --
*
* Return the size of the trap stack. This can vary depending on whether
* are on a Sun-3 or a Sun-2.
*
* Results:
* Trap stack size.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
Mach_GetExcStackSize(excStackPtr)
Mach_ExcStack *excStackPtr;
{
switch (excStackPtr->vor.stackFormat) {
case MACH_SHORT:
return(MACH_SHORT_SIZE);
case MACH_THROWAWAY:
return(MACH_THROWAWAY_SIZE);
case MACH_INST_EXCEPT:
return(MACH_INST_EXCEPT_SIZE);
case MACH_MC68010_BUS_FAULT:
return(MACH_MC68010_BUS_FAULT_SIZE);
case MACH_COPROC_MID_INSTR:
return(MACH_COPROC_MID_INSTR_SIZE);
case MACH_SHORT_BUS_FAULT:
return(MACH_SHORT_BUS_FAULT_SIZE);
case MACH_LONG_BUS_FAULT:
return(MACH_LONG_BUS_FAULT_SIZE);
default:
printf("Warning: Mach_GetTrapStackSize: Bad stack format.\n");
return(-1);
}
}
/*
* ----------------------------------------------------------------------------
*
* Mach_ProcessorState --
*
* Determines what state the processor is in.
*
* Results:
* MACH_USER if was at user level
* MACH_KERNEL if was at kernel level
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
Mach_ProcessorStates
Mach_ProcessorState(processor)
int processor; /* processor number for which info is requested */
{
if (mach_KernelMode) {
return(MACH_KERNEL);
} else {
return(MACH_USER);
}
}
/*
* ----------------------------------------------------------------------------
*
* Mach_GetMachineArch --
*
* Return the machine architecture (SYS_SUN2 or SYS_SUN3).
*
* Results:
* The machine architecture.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
Mach_GetMachineArch()
{
# ifdef sun2
return SYS_SUN2;
# endif sun2
# ifdef sun3
return SYS_SUN3;
# endif sun3
}
/*
* ----------------------------------------------------------------------------
*
* Mach_CheckSpecialHandling--
*
* Forces a processor to check the special handling flag of a process.
* This should only be called on a multiprocessor.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
void
Mach_CheckSpecialHandling(pnum)
int pnum; /* Processor number. */
{
panic("Mach_CheckSpecialHandling called for processor %d\n",pnum);
}
/*
*----------------------------------------------------------------------
*
* Mach_GetNumProcessors() --
*
* Return the number of processors in the system. NOTE: This should
* really be in a machine-independent area of the mach module. Note
* further: if this is used only as a system call, it should return
* a ReturnStatus!
*
* Results:
* The number of processors is returned.
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
int
Mach_GetNumProcessors()
{
return (mach_NumProcessors);
}
/*
*----------------------------------------------------------------------
*
* Mach_GetBootArgs --
*
* Returns the arguments out of the boot parameter structure.
*
* Results:
* Number of elements returned in argv.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Mach_GetBootArgs(argc, bufferSize, argv, buffer)
int argc; /* Number of elements in argv */
int bufferSize; /* Size of buffer */
char **argv; /* Ptr to array of arg pointers */
char *buffer; /* Storage for arguments */
{
int i;
int offset;
bcopy(machMonBootParam.strings, buffer,
(bufferSize < 100) ? bufferSize : 100);
offset = (int) machMonBootParam.strings - (int) buffer;
for(i = 0; i < argc; i++) {
if (machMonBootParam.argPtr[i] == (char *) 0 ||
machMonBootParam.argPtr[i] == (char *) NIL) {
break;
}
argv[i] = (char *) (machMonBootParam.argPtr[i] - (char *) offset);
}
return i;
}
/*
*----------------------------------------------------------------------
*
* Mach_SigreturnStub --
*
* Procedure to map from Unix sigreturn system call to Sprite.
* This is used for returning from longjmps and signals.
*
* Results:
* Error code is returned upon error. Otherwise SUCCESS is returned.
*
* Side effects:
* Changes the stack, pc, etc. to the specified values.
*
*----------------------------------------------------------------------
*/
int
Mach_SigreturnStub()
{
Proc_ControlBlock *procPtr = Proc_GetActualProc();
Mach_ExcStack *excStackPtr;
int excStackSize;
int bufVals[5];
int *jmpBuf;
Vm_CopyIn(sizeof(int), procPtr->machStatePtr->userState.userStackPtr,
(Address)&jmpBuf);
if (Vm_CopyIn(5*sizeof(int), (Address)jmpBuf, (Address)bufVals) !=
SUCCESS) {
printf("JmpBuf copy in failure\n");
return -1;
}
if (Sig_SigsetmaskStub(bufVals[1])<0) {
printf("Sig_SigsetmaskStub error in Sigreturn on %x\n", bufVals[1]);
}
if (debugProcStubs) {
printf("saved usp = %x, SP= %x, exSp = %x\n",
procPtr->machStatePtr->userState.userStackPtr,
procPtr->machStatePtr->userState.trapRegs[SP],
procPtr->machStatePtr->userState.excStackPtr);
printf("Mach_SigreturnStub(%x from %x): %x, %x, %x, %x, %x\n", jmpBuf,
procPtr->machStatePtr->userState.userStackPtr,
bufVals[0], bufVals[1],
bufVals[2], bufVals[3], bufVals[4]);
}
procPtr->machStatePtr->userState.userStackPtr = (Address)bufVals[2];
/*
* We need to make a short stack to allow the process to start executing.
* The current exception stack is at least as big, maybe bigger than we
* need. Since we saved the true exception stack above, we can just
* overwrite the current stack with a short stack and point the stack
* pointer at it.
*/
excStackSize = Mach_GetExcStackSize(procPtr->machStatePtr->
userState.excStackPtr);
excStackPtr = (Mach_ExcStack *) ((Address)procPtr->machStatePtr
->userState.excStackPtr + excStackSize - MACH_SHORT_SIZE);
procPtr->machStatePtr->userState.trapRegs[SP] = (int)excStackPtr;
excStackPtr->statusReg = bufVals[4]&0xf;
if (debugProcStubs) {
printf("Sigreturn statusReg = %x, pc = %x\n", bufVals[4]&0xf,
bufVals[3]);
}
excStackPtr->vor.stackFormat = MACH_SHORT;
excStackPtr->pc = (int)bufVals[3];
if (debugProcStubs) {
printf("New usp = %x, SP= %x, exSp = %x\n",
procPtr->machStatePtr->userState.userStackPtr,
procPtr->machStatePtr->userState.trapRegs[SP],
procPtr->machStatePtr->userState.excStackPtr);
}
return procPtr->machStatePtr->userState.trapRegs[D0];
}